#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include <unistd.h>
#include <ctime>
#include "processpool.hpp"

using namespace std;

enum
{
    UsageError=1,
    SubProcessError,
    PipeError
}

void Usage(const string &proc)
{
    cout<<"Usage:"<<proc<<"subprocess-num"<<endl;
}

class Channel
{
public:
    Channel(int wfd,int sub_process_id,string name)
    :_wfd(wfd)
    ,_sub_process_id(sub_process_id)
    ,_name(name)
    {
    }

    void PrintDebug()
    {
        cout<<"_wfd:"<<wfd<<endl;
        cout<<"_sub_process_id:"<<sub_process_id<<endl;
        cout<<"_name:"<<name<<endl;
    }

    ~Channel()
    {}

private:
    int _wfd;
    pid_t _sub_process_id;
    string _name;
};

class Processpool
{
public:
    Processpool(int sub_process_num)
    :_sub_process_num(sub_process_num);
    {
    }

    int CreateProcess(work_t work)
    {
        for(int num=0;num<_sub_process_num;num++)
        {
            int pipefd[2]{0};
            int n=pipe(pipefd);
            if(n<0)
            {
                return PipeError;
            }

            pid_t id=fork();
            if(id==0)
            {
                // child  r
                close(pipefd[1]);
                dup2(pipefd[0],0);
                work();
                exit(0);
            }

            // father  w
            close(pipefd[0]);
            string cname="channel-"+to_string(num);
            channels.push_back(Channel(pipefd[1],num,cname));
        }
        return 0;
    }

    int NextChannel()
    {
        int next=0;
        int c=next;
        next++;
        int next=next%_sub_process_num;
        return c;
    }

    void SendTaskCode(int index,uint32_t code)
    {
        cout << "send code: " << code << " to " << channels[index].name() << " sub prorcess id: " <<  channels[index].pid() << endl;
        write(channels[index].wfd(), &code, sizeof(code));
    }

    void Debug()
    {
        for(auto &channel:channels)
        {
            channel.PrintDebug();
        }
    }

    ~Processpool()
    {}

private:
    int _sub_process_num;
    vector<Channel> channels;
};

int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        Usage(argv[0]);
        return UsageError;  //返回错误码
    }
    int sub_process_num=stoi(argv[1]);
    if(sub_process_num<=0)
    {
        Usage(argv[0]);
        return SubProcessError;
    }

    // 1、创建通道和子进程
    Processpool *processpool_ptr=new Processpool(sub_process_num);
    processpool_ptr->CreateProcess();

    // 2、控制子进程
    while(true)
    {
        int channel=processpool_ptr->NextChannel();

        uini32_t code=NextTask();

        processpool_ptr->SendTaskCode(channel,code);

        sleep(1);
    }
    // 3、回收子进程
    delete processpool_ptr;

    return 0;
}